package com.tbl.modules.wms.service.Impl.allo;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.tbl.common.utils.*;
import com.tbl.modules.wms.constant.Constant;
import com.tbl.modules.wms.constant.EmumConstant;
import com.tbl.modules.wms.dao.allo.AlloInStorageDAO;
import com.tbl.modules.wms.dao.allo.AlloOutStorageDAO;
import com.tbl.modules.wms.dao.allo.AllocationDAO;
import com.tbl.modules.wms.dao.allo.AllocationDetailDAO;
import com.tbl.modules.wms.dao.baseinfo.CarDAO;
import com.tbl.modules.wms.dao.baseinfo.ShelfDAO;
import com.tbl.modules.wms.dao.baseinfo.WarehouseDAO;
import com.tbl.modules.wms.dao.instorage.InstorageDetailDAO;
import com.tbl.modules.wms.dao.move.MoveStorageDAO;
import com.tbl.modules.wms.dao.pda.SplitDAO;
import com.tbl.modules.wms.dao.storageinfo.StorageInfoDAO;
import com.tbl.modules.wms.entity.allo.AlloInStorage;
import com.tbl.modules.wms.entity.allo.AlloOutStorage;
import com.tbl.modules.wms.entity.allo.Allocation;
import com.tbl.modules.wms.entity.allo.AllocationDetail;
import com.tbl.modules.wms.entity.baseinfo.Car;
import com.tbl.modules.wms.entity.baseinfo.Shelf;
import com.tbl.modules.wms.entity.baseinfo.Warehouse;
import com.tbl.modules.wms.entity.instorage.InstorageDetail;
import com.tbl.modules.wms.entity.split.Split;
import com.tbl.modules.wms.entity.storageinfo.StorageInfo;
import com.tbl.modules.wms.service.Impl.baseinfo.ShelfServiceImpl;
import com.tbl.modules.wms.service.Impl.webserviceImpl.WmsServiceImpl;
import com.tbl.modules.wms.service.allo.AllocationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 调拨管理
 * @author 70486
 */
@Service
public class AllocationServiceImpl extends ServiceImpl<AllocationDAO, Allocation> implements AllocationService {

    /**
     * 调拨管理
     */
    @Autowired
    private AllocationDAO allocationDAO;
    /**
     * 调拨管理详情
     */
    @Autowired
    private AllocationDetailDAO allocationDetailDAO;
    /**
     * 库存
     */
    @Autowired
    private StorageInfoDAO storageInfoDAO;
    /**
     * 仓库
     */
    @Autowired
    private WarehouseDAO warehouseDAO;
    /**
     * 行车
     */
    @Autowired
    private CarDAO carDAO;
    /**
     * 库位
     */
    @Autowired
    private ShelfDAO shelfDAO;
    /**
     * 调拨入库
     */
    @Autowired
    private AlloInStorageDAO alloInStorageDAO;
    /**
     * 调拨出库
     */
    @Autowired
    private AlloOutStorageDAO alloOutStorageDAO;
    /**
     * 调用接口执行
     */
    @Autowired
    private WmsServiceImpl wmsServiceImpl;
    /**
     * 移库处理
     */
    @Autowired
    private MoveStorageDAO moveStorageDAO;
    /**
     * 库位
     */
    @Autowired
    private ShelfServiceImpl shelfImpl;
    /**
     * 标签
     */
    @Autowired
    private InstorageDetailDAO instorageDetailDAO;
    /**
     * 拆分表
     */
    @Autowired
    private SplitDAO splitDAO;

    /**
     * 调拨单管理列表页数据
     * @param pageTbl
     * @param map
     * @return PageUtils
     */
    @Override
    public PageUtils getPageList(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();

        if (StringUtils.isEmptyString(sortName)|| "ALLOSTATE".equalsIgnoreCase(sortName) ||"startOutTime".equals(sortName)
                ||"endInTime".equals(sortName)||"state".equals(sortName)) {
        	sortName = "t1.id";
        }else if("factoryName".equals(sortName)){
        	sortName = "t1.id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
        	sortOrder = "desc";
        }

        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(allocationDAO.getPageList(page, map)));
    }

    /**
     * 移库调拨单管理列表页数据
     * @param pageTbl
     * @param map
     * @return PageUtils
     */
    @Override
    public PageUtils getMoveAlloPageList(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();

        if (StringUtils.isEmptyString(sortName)|| "ALLOSTATE".equalsIgnoreCase(sortName) ||"startOutTime".equals(sortName)
                ||"endInTime".equals(sortName)||"state".equals(sortName)) {
            sortName = "t1.id";
        }else if("factoryName".equals(sortName)){
            sortName = "t1.id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }

        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(allocationDAO.getMoveAlloPageList(page, map)));
    }

    /**
     * 调拨单获取详情的列表
     * @param pageTbl
     * @param id 调拨单主键
     * @return PageUtils
     */
    @Override
    public PageUtils getPageDetailList(PageTbl pageTbl, Integer id) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName)) {
            sortName = "id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(allocationDAO.getDetailList(page, id)));
    }

    /**
     * 移库调拨单获取详情的列表
     * @param pageTbl
     * @param id 移库调拨单主键
     * @return PageUtils
     */
    @Override
    public PageUtils getMoveAlloPageDetailList(PageTbl pageTbl, Integer id) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName)) {
            sortName = "id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(allocationDAO.getMoveAlloDetailList(page, id)));
    }
    
    /**
     * 点击保存，保存主表信息
     * @param allocation 调拨单
     * @return Long 调拨单主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveAllocation(Allocation allocation) {
        Warehouse inWarehouse = warehouseDAO.selectById(allocation.getInWarehouseId());
        if (allocation.getId() != Constant.SIGN_ADD) {
            allocationDetailDAO.deleteByMap(new HashMap<String, Object>() {{
                put("PID", allocation.getId());
            }});
            allocation.setInWarehouseCode(inWarehouse.getCode());
            this.insertOrUpdate(allocation);

            AllocationDetail allocationDetailEntity = new AllocationDetail();
            allocationDetailEntity.setInWarehouseCode(inWarehouse.getCode());
            allocationDetailDAO.update(allocationDetailEntity, new EntityWrapper<AllocationDetail>().eq("P_ID", allocation.getId()));
        } else {
            Warehouse outWarehouse = warehouseDAO.selectById(allocation.getOutWarehouseId());
            String serial = new DecimalFormat("0000").format(allocationDAO.selectLatestAllocation() + 1);
            allocation.setAllCode("DB" + DateUtils.getDays() + serial);
            allocation.setMoveTime(new Date());
            allocation.setInWarehouseCode(inWarehouse.getCode());
            allocation.setOutWarehouseCode(outWarehouse.getCode());
            allocation.setInWarehouseId(inWarehouse.getId());
            allocation.setOutWarehouseId(outWarehouse.getId());
            this.insertOrUpdate(allocation);
            moveStorageDAO.updateSerial(serial,Constant.SERIAL_ALLO);
        }
        return allocation.getId();
    }

    /**
     * 移库单管理点击提交
     * @param allocation 移库单
     * @return Map<String,Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> subAllocation(Allocation allocation) {
        Map<String, Object> map = new HashMap<>();
        List<AllocationDetail> lstAllocationDetail = allocationDetailDAO.selectByMap(new HashMap<String, Object>() {{
            put("PID", allocation.getId());
        }});
        if (lstAllocationDetail == null || lstAllocationDetail.size() == 0) {
            map.put("result", false);
            map.put("msg", "请选择质保单号！");
            return map;
        }
        Warehouse inWarehouse = warehouseDAO.selectById(allocation.getInWarehouseId());
        allocation.setMoveTime(new Date());
        allocation.setInWarehouseCode(inWarehouse.getCode());
        allocation.setState(Constant.INT_TWO);//状态设置为已提交
        this.insertOrUpdate(allocation);

        AllocationDetail allocationDetail = new AllocationDetail();
        allocationDetail.setInWarehouseCode(inWarehouse.getCode());
        allocationDetailDAO.update(allocationDetail, new EntityWrapper<AllocationDetail>().eq("P_ID", allocation.getId()));

        map.put("result", true);
        map.put("msg", "提交成功！");
        return map;
    }

    /**
     * 编辑页面  获取质保单号列表
     * @param pageTbl
     * @param map
     * @return PageUtils
     */
    @Override
    public PageUtils getQaCode(PageTbl pageTbl, Map<String, Object> map) {
        Page<Map<String, Object>> page = new Page<>(pageTbl.getPageno(), pageTbl.getPagesize());
        return new PageUtils(page.setRecords(allocationDAO.getQaCode(page, map)));
    }

    /**
     * 调拨单新增详情数据
     * @param id 调拨单主键
     * @param qaCodeIds 库存主键
     * @param factoryCode 调出厂区编码
     * @param userId 操作员主键
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveAllocationDetail(Long id, String[] qaCodeIds, String factoryCode, Long userId) {
        //这些主键有可能是库存表中的，有可能是拆分表中的（后改：不会冲突因为序列不一样）
        List<Long> lstStorageInfoId = StringUtils.toLongList(qaCodeIds);
        //库存中的数据
        List<StorageInfo> lstStorageInfo = storageInfoDAO.selectList(new EntityWrapper<StorageInfo>().in("ID", lstStorageInfoId));
        //拆分表中的数据
        List<Split> lstSplit = splitDAO.selectList(new EntityWrapper<Split>().in("ID", lstStorageInfoId));

        List<AllocationDetail> allocationDetailBatches = new LinkedList<>();
        Allocation allocation = allocationDAO.selectById(id);

        lstStorageInfo.forEach(storageInfo -> {
            AllocationDetail allocationDetail = new AllocationDetail();
            allocationDetail.setMaterialCode(storageInfo.getMaterialCode());
            allocationDetail.setMeter(storageInfo.getMeter());
            allocationDetail.setRfid(storageInfo.getRfid());
            allocationDetail.setPId(id);
            allocationDetail.setQaCode(storageInfo.getQaCode());
            allocationDetail.setBatchNo(storageInfo.getBatchNo());
            allocationDetail.setOrg(allocation.getInFactoryCode());
            allocationDetail.setOutWarehouseCode(allocation.getOutWarehouseCode());
            allocationDetail.setInWarehouseCode(allocation.getInWarehouseCode());
            allocationDetail.setOutShelfCode(storageInfo.getShelfCode());
            allocationDetail.setDishnumber(storageInfo.getDishnumber());
            allocationDetail.setOutStorageId(userId);
            allocationDetail.setStartOutStorageTime(new Date());
            allocationDetailBatches.add(allocationDetail);
        });

        lstSplit.forEach(split -> {
            AllocationDetail allocationDetail = new AllocationDetail();
            allocationDetail.setMaterialCode(split.getMaterialCode());
            allocationDetail.setMeter(split.getMeter());
            allocationDetail.setRfid(split.getRfid());
            allocationDetail.setPId(id);
            allocationDetail.setQaCode(split.getQaCode());
            allocationDetail.setBatchNo(split.getBatchNo());
            allocationDetail.setOrg(allocation.getInFactoryCode());
            allocationDetail.setOutWarehouseCode(allocation.getOutWarehouseCode());
            allocationDetail.setInWarehouseCode(allocation.getInWarehouseCode());
            allocationDetail.setOutShelfCode(split.getShelfCode());
            allocationDetail.setDishnumber(split.getDishnumber());
            allocationDetail.setOutStorageId(userId);
            allocationDetail.setStartOutStorageTime(new Date());
            allocationDetailBatches.add(allocationDetail);
        });

        //批量插入
        if (allocationDetailBatches.size()>0){
            allocationDetailDAO.insertBatches(allocationDetailBatches);
        }

        StorageInfo storageInfo = new StorageInfo();
        storageInfo.setState(EmumConstant.storageInfoState.LOCKING.getCode());
        storageInfoDAO.update(storageInfo, new EntityWrapper<StorageInfo>().in("ID", lstStorageInfoId));
        return true;
    }

    /**
     * 删除调拨单下的明细数据
     * @param ids 调拨表详情表主键
     * @return Map<String,Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> deleteAllocationDetailIds(String[] ids) {
        Map<String, Object> map = new HashMap<>();
        AtomicBoolean result = new AtomicBoolean(true);
        List<Long> idList = StringUtils.toLongList(ids);
        List<Long> lstAllocationDetailState = allocationDetailDAO.getAllocationDetailStateList(idList);

        if (lstAllocationDetailState.contains(Long.valueOf(EmumConstant.locationChangeStatus.START_CHANGE_OUT.getCode())) ||
                lstAllocationDetailState.contains(Long.valueOf(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_OUT.getCode())) ||
                lstAllocationDetailState.contains(Long.valueOf(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode())) ||
                lstAllocationDetailState.contains(Long.valueOf(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_IN.getCode()))) {
            map.put("msg", "已经开始出入库流程，请勿删除！");
            map.put("result", result.get());
            return map;
        }

        //删除数据，需要在库存表解冻该条物料
        StorageInfo storageInfo = new StorageInfo();
        storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
        storageInfoDAO.update(storageInfo, new EntityWrapper<StorageInfo>()
                .in("QACODE",allocationDetailDAO.getAllocationDetailQacodeList(idList)));
        //删除调拨明细
        allocationDetailDAO.deleteBatchIds(idList);

        map.put("msg", result.get()?"删除成功！":"删除失败！");
        map.put("result", result.get());
        return map;
    }

    /**
     * 删除调拨单以及对应的调拨单下的详情数据
     * @param ids 调拨单主键
     * @return Map<String,Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> deleteByIds(String[] ids) {
        List<String> lstQaCode = new LinkedList<>();
        List<AllocationDetail> lstAllocationDetail = allocationDetailDAO.selectList(new EntityWrapper<AllocationDetail>()
                .in("PID", ids));
        lstAllocationDetail.forEach(allocationDetail -> lstQaCode.add(allocationDetail.getQaCode()));

        //更新库存的状态为 正常
        StorageInfo storageInfo = new StorageInfo();
        storageInfo.setState(Constant.INT_ONE);
        storageInfoDAO.update(storageInfo, new EntityWrapper<StorageInfo>().in("QACODE", lstQaCode));

        Map<String, Object> map = new HashMap<>();
        List<Long> infoIdList = StringUtils.toLongList(ids);
        if (allocationDAO.selectDetailsState(infoIdList) > 0) {
            map.put("msg", "该调拨单已经开始进行出库入库操作，请勿删除!");
            map.put("result", false);
            return map;
        }

        allocationDetailDAO.delete(new EntityWrapper<AllocationDetail>().in("PID", infoIdList));
        allocationDAO.deleteBatchIds(infoIdList);

        map.put("msg", "删除成功！");
        map.put("result", true);
        return map;
    }

    /**
     * 获取调入仓库的数据
     * @param pageTbl
     * @param map
     * @return PageUtils
     */
    @Override
    public PageUtils selectWarehouseIn(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName)) {
            sortName = "id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(allocationDAO.selectWarehouseIn(page, map)));
    }

    /**
     *  获取调出仓库的数据
     *  @param pageTbl
     *  @param map
     * @return PageUtils
     */
    @Override
    public PageUtils selectWarehouseOut(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName)) {
            sortName = "id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(allocationDAO.selectWarehouseOut(page, map)));
    }

    /**
     * 根据主键获取主表信息
     * @param id 调拨单主键
     * @return Allocation 调拨单
     */
    @Override
    public Allocation selectInfoById(Long id) {
        return allocationDAO.selectInfoById(id,allocationDAO.selectById(id).getFactoryCode());
    }

    /**
     * 点击编辑，点击保存  保存主表信息
     * @param allocation 调拨单
     * @return boolean
     */
    @Override
    public boolean saveAlloOutStorage(Allocation allocation) {
        return this.insertOrUpdate(allocation);
    }

    /**
     * 点击编辑，点击提交，修改状态
     * @param allocation 调拨单
     * @return boolean
     */
    @Override
    public boolean subAlloOutStorage(Allocation allocation) {
        return this.insertOrUpdate(allocation);
    }

    /**
     * 跳转行车绑定页面获取行车绑定列表
     * @param warehouseCode 仓库编码
     * @param org 厂区编码
     * @return List<Car> 行车列表
     */
    @Override
    public List<Car> selectCarListByWarehouseCode(String warehouseCode,List<String> org) {
        return allocationDAO.selectCarListByWarehouseCode(warehouseCode,org);
    }

    /**
     * 点击出库执行，点击绑定行车  点击保存行车信息
     * @param allocationDetail 调拨表详情
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveCar(AllocationDetail allocationDetail) {
        allocationDetail.setOutCarCode(carDAO.selectById(allocationDetail.getCarId()).getCode());
        return allocationDetailDAO.updateById(allocationDetail)>0;
    }

    /**
     * 点击出库执行，点击开始拣货
     * @param id 调拨详情主键
     * @return boolean
     */
    @Override
    public boolean detailStart(Long id) {
        AllocationDetail allocationDetail = allocationDetailDAO.selectById(id);
        allocationDetail.setState(Constant.INT_TWO);
        allocationDetail.setStartOutStorageTime(new Date());//出库拣货时间
        Car car = carDAO.selectOne(new Car() {{
        	setCode(allocationDetail.getOutCarCode());
        }});
        if(car!=null) {
        	car.setState(Long.valueOf(EmumConstant.carState.OUTSTORAGING.getCode()));
        	carDAO.updateById(car);
        }
        return allocationDetailDAO.updateById(allocationDetail)>0;
    }

    /**
     * 点击出库执行，点击拣货完成
     * @param id 调拨单明细主键
     * @param userId 用户主键
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean detailSuccess(Long id, Long userId) {
        AllocationDetail allocationDetail = allocationDetailDAO.selectById(id);
        storageInfoDAO.deleteByMap(new HashMap<String, Object>() {{
            put("QACODE", allocationDetail.getQaCode());
        }});

        Allocation allocation = allocationDAO.selectById(allocationDetail.getPId());

        AlloOutStorage alloOutStorage = new AlloOutStorage();
        alloOutStorage.setBatchNo(allocationDetail.getBatchNo());
        alloOutStorage.setMaterialCode(allocationDetail.getMaterialCode());
        alloOutStorage.setBatchNo(allocationDetail.getBatchNo());
        alloOutStorage.setQaCode(allocationDetail.getQaCode());
        alloOutStorage.setRfid(allocationDetail.getRfid());
        alloOutStorage.setMeter(allocationDetail.getMeter());
        alloOutStorage.setCarCode(allocationDetail.getOutCarCode());
        alloOutStorage.setOrg(allocationDetail.getOrg());
        alloOutStorage.setOutstoragetime(new Date());
        alloOutStorage.setWarehouseCode(allocation.getOutWarehouseCode());
        alloOutStorage.setShelfCode(allocationDetail.getOutShelfCode());
        alloOutStorage.setState(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        alloOutStorage.setDishnumber(allocationDetail.getDishnumber());
        alloOutStorageDAO.insert(alloOutStorage);

        allocationDetail.setState(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_OUT.getCode());
        //加入完成拣货人的id
        allocationDetail.setOutStorageId(userId);
        allocationDetail.setOutStorageTime(new Date());
        allocationDetail.setStartOutStorageTime(new Date());
        /*carDAO.updateCarByCode(allocationDetail.getOutCarCode(),"",Constant.LONG_TWO);*/
        //库位可用
        shelfImpl.setShelfState(allocationDetail.getOutShelfCode(),allocation.getFactoryCode(),allocation.getOutWarehouseCode(),
                Constant.INT_ZERO);
        return allocationDetailDAO.updateById(allocationDetail)>0;
    }


    /**
     * 调拨出库批量完成出库
     * @param lstIds 调拨单明细主键数组
     * @param userId 用户主键
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String,Object> allStorageOut(List<Long> lstIds, Long userId) {
        Map<String,Object> resultMap = Maps.newHashMap();

        if (lstIds == null || lstIds.size() == 0){
            resultMap.put("result", false);
            resultMap.put("msg","所选货物都已调拨出库完毕，无需再次出库！");
            return resultMap;
        }

        //批量调拨出库的明细
        List<AllocationDetail> lstAllocationDetail = allocationDetailDAO.selectBatchIds(lstIds);
        //待插入调拨出库表的明细
        List<AlloOutStorage> lstAlloOutStorage = new ArrayList<>();

        List<String> lstQaCode = new ArrayList<>();
        List<String> lstCarCode = new ArrayList<>();
        List<Shelf> lstShelf = new ArrayList<>();
        List<Long> lstStorageInfoIds = new ArrayList<>();

        lstAllocationDetail.forEach(allocationDetail->{
            lstQaCode.add(allocationDetail.getQaCode());

            Allocation allocation = allocationDAO.selectById(allocationDetail.getPId());
            AlloOutStorage alloOutStorage = new AlloOutStorage();
            alloOutStorage.setBatchNo(allocationDetail.getBatchNo());
            alloOutStorage.setMaterialCode(allocationDetail.getMaterialCode());
            alloOutStorage.setQaCode(allocationDetail.getQaCode());
            alloOutStorage.setRfid(allocationDetail.getRfid());
            alloOutStorage.setMeter(allocationDetail.getMeter());
            alloOutStorage.setCarCode(allocationDetail.getOutCarCode());
            alloOutStorage.setOrg(allocationDetail.getOrg());
            alloOutStorage.setOutstoragetime(new Date());
            alloOutStorage.setWarehouseCode(allocation.getOutWarehouseCode());
            alloOutStorage.setShelfCode(allocationDetail.getOutShelfCode());
            alloOutStorage.setState(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
            alloOutStorage.setDishnumber(allocationDetail.getDishnumber());
            lstAlloOutStorage.add(alloOutStorage);
            //添加行车编码
            if (StringUtils.isNotEmpty(allocationDetail.getOutCarCode())){
                lstCarCode.add(allocationDetail.getOutCarCode());
            }

            //添加库位（置空的库位）
            List<Shelf> shelfList = shelfDAO.selectList(new EntityWrapper<Shelf>()
                    .eq("CODE", allocationDetail.getOutShelfCode())
                    .eq("FACTORYCODE", allocation.getFactoryCode())
                    .eq("WAREHOUSECODE", allocationDetail.getOutWarehouseCode()));

            if (shelfList!=null && shelfList.size()>0){
                lstShelf.add(shelfList.get(0));
            }

        });

        //批量插入调拨出库表
        if (lstAlloOutStorage.size()>0){
            alloOutStorageDAO.insertAlloOutstorageBatch(lstAlloOutStorage);
        }
        //批量删除库存
        List<StorageInfo> lstStorageInfo = storageInfoDAO.selectList(new EntityWrapper<StorageInfo>().in("QACODE",lstQaCode));
        lstStorageInfo.forEach(storageInfo -> lstStorageInfoIds.add(storageInfo.getId()));
        if (lstStorageInfoIds.size()>0){
            storageInfoDAO.deleteBatchIds(lstStorageInfoIds);
        }

        //批量添加调拨单明细的状态，添加调拨人员
        AllocationDetail allocationDetail = new AllocationDetail();
        allocationDetail.setState(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_OUT.getCode());
        allocationDetail.setOutStorageId(userId);
        allocationDetail.setStartOutStorageTime(new Date());
        allocationDetail.setOutStorageTime(new Date());
        allocationDetailDAO.update(allocationDetail,new EntityWrapper<AllocationDetail>().in("ID",lstIds));

        //批量设置库位可用
        lstShelf.forEach(shelf -> shelf.setState(1));
        shelfDAO.updateBatches(lstShelf);

        //批量设置行车可用
        if (lstCarCode.size()>0){
            Car car = new Car();
            car.setState(Long.valueOf(EmumConstant.carState.UNUSED.getCode()));
            carDAO.update(car, new EntityWrapper<Car>().in("CODE", lstCarCode));
        }

        resultMap.put("result", true);
        resultMap.put("msg","调拨出库成功！");
        return resultMap;
    }

    /**
     * 获取调拨入库列表数据
     * @param pageTbl
     * @param map
     * @return PageUtils
     */
    @Override
    public PageUtils getInDetailList(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName) || "cz".equalsIgnoreCase(sortName)) {
        	sortName = "t1.id";
        }else if("state".equals(sortName)){
        	sortName = "t1.state";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(allocationDAO.getInDetailList(page, map)));
    }

    /**
     * 获取行车列表
     * @param id 仓库主键
     * @return List<Car> 行车列表
     */
    @Override
    public List<Car> getCarList(Long id) {
        return allocationDAO.getCarList(id);
    }

    /**
     * 点击开始入库更新仓库，行车，状态信息
     * @param allocationDetail 调拨详情
     */
    @Override
    public void updateDetail(AllocationDetail allocationDetail) {
        Car car = carDAO.selectById(allocationDetail.getCarId());
        allocationDetail.setState(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        allocationDetail.setStartInStorageTime(new Date());
        allocationDetail.setInCarCode(car.getCode());
        car.setState(Long.valueOf(EmumConstant.carState.OUTSTORAGING.getCode()));
        carDAO.updateById(car);
        allocationDetailDAO.updateById(allocationDetail);
    }

    /**
     * 选择库位
     * @param pageTbl
     * @param map
     * @return PageUtils
     */
    @Override
    public PageUtils selectUnbindShelf(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName)) {
            sortName = "t1.id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(allocationDAO.selectUnbindShelf(page, map)));
    }

    /**
     * 功能描述:入库确认
     * @param id 调拨/移库 详情主键
     * @param shelfId 库位主键
     * @param userId 用户主键
     * @return Map<String, Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> confirmInstorage(Long id, Long shelfId, Long userId) {
        Map<String, Object> resultMap = Maps.newHashMap();
        Shelf shelf = shelfDAO.selectById(shelfId);
        AllocationDetail allocationDetail = allocationDetailDAO.selectById(id);
        //判断重复库位
        if(shelf.getCode().equals(allocationDetail.getOutShelfCode())){
            resultMap.put("result", false);
            resultMap.put("msg", "入库的库位与出库的库位相同，不能重复移库，请检查！");
            return resultMap;
        }
        InstorageDetail instorageDetail = instorageDetailDAO.selectOne(new InstorageDetail(){{
            setRfid(allocationDetail.getRfid());
        }});

        Split split = splitDAO.selectOne(new Split(){{
            setRfid(allocationDetail.getRfid());
        }});

        boolean interfaceExecuteResult;
        try {
            //调EBS移库调拨接口
            Map<String,Object> xmlMap = new HashMap<>();
            xmlMap.put("line",new HashMap<String,Object>(){{
                put("org",instorageDetail == null ? split.getOrg() : instorageDetail.getOrg());
                put("batchno",allocationDetail.getBatchNo());
                put("qacode",allocationDetail.getQaCode());
                //新仓库
                put("inwarehouse",allocationDetail.getInWarehouseCode());
                //新库位
                put("inLocation",shelf.getCodeComplete());
            }});
            //实时调用移库调拨接口
            String returnInfo = wmsServiceImpl.FEWMS008(xmlMap, allocationDetail.getQaCode(), allocationDetail.getBatchNo());
            String returnInfoTrim = returnInfo.replace(" ", "");
            //接口执行结果
            interfaceExecuteResult = returnInfoTrim.contains("<code>0</code>") || returnInfoTrim.contains("\"code\":0") ||
                    returnInfoTrim.contains("S000A000");
            //接口执行失败，直接返回，不做下面的任何更新操作，因为失败后，用户还需要再次点击，成功后才能更新
            if (!interfaceExecuteResult){
                //根据接口执行结果把实时结果（返回报文）展示到前台界面
                resultMap.put("result", false);
                resultMap.put("msg", "接口执行失败：" + returnInfo);
                return resultMap;
            }else {
                resultMap.put("result", true);
                resultMap.put("msg", "入库成功！");
            }
        } catch (Exception e) {
            e.printStackTrace();
            resultMap.put("result", false);
            resultMap.put("msg", "系统错误，请联系管理员！");
            return resultMap;
        }

        //更新移库调拨明细详情
        allocationDAO.confirmInstorage(id, shelf.getCode(),userId);

        Allocation allocation = allocationDAO.selectById(allocationDetail.getPId());
        AlloInStorage alloInStorage = new AlloInStorage();
        alloInStorage.setMaterialCode(allocationDetail.getMaterialCode());
        alloInStorage.setBatchNo(allocationDetail.getBatchNo());
        alloInStorage.setQaCode(allocationDetail.getQaCode());
        alloInStorage.setShelfCode(allocationDetail.getInShelfCode());
        alloInStorage.setWarehouseCode(allocationDetail.getInWarehouseCode());
        alloInStorage.setMeter(allocationDetail.getMeter());
        alloInStorage.setInstorageTime(new Date());
        alloInStorage.setOrg(allocation.getInFactoryCode());
        alloInStorage.setRfid(allocationDetail.getRfid());
        alloInStorage.setCarCode(allocationDetail.getInCarCode());
        alloInStorage.setInStorageId(userId);
        alloInStorage.setDishnumber(allocationDetail.getDishnumber());
        alloInStorageDAO.insert(alloInStorage);

        AlloOutStorage alloOutStorage = new AlloOutStorage();
        alloOutStorage.setBatchNo(allocationDetail.getBatchNo());
        alloOutStorage.setMaterialCode(allocationDetail.getMaterialCode());
        alloOutStorage.setQaCode(allocationDetail.getQaCode());
        alloOutStorage.setRfid(allocationDetail.getRfid());
        alloOutStorage.setMeter(allocationDetail.getMeter());
        alloOutStorage.setCarCode(allocationDetail.getOutCarCode());
        alloOutStorage.setOrg(allocationDetail.getOrg());
        alloOutStorage.setOutstoragetime(new Date());
        alloOutStorage.setWarehouseCode(allocation.getOutWarehouseCode());
        alloOutStorage.setShelfCode(allocationDetail.getOutShelfCode());
        alloOutStorage.setState(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        alloOutStorage.setDishnumber(allocationDetail.getDishnumber());
        alloOutStorageDAO.insert(alloOutStorage);

        StorageInfo storageInfo = storageInfoDAO.selectOne(new StorageInfo(){{
            setRfid(allocationDetail.getRfid());
        }});
        storageInfo.setShelfCode(allocationDetail.getInShelfCode());
        storageInfo.setWarehouseCode(allocationDetail.getInWarehouseCode());
        storageInfo.setOrg(allocation.getInFactoryCode());
        storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
        storageInfoDAO.updateById(storageInfo);

        //更新行车状态
        carDAO.updateCarByCode(allocationDetail.getInCarCode(), "", Long.valueOf(EmumConstant.carState.UNUSED.getCode()));
        //更新库位状态
        shelfImpl.setShelfState(shelf.getCode(),allocation.getInFactoryCode(),allocation.getInWarehouseCode(),0);
        shelfImpl.setShelfState(allocationDetail.getOutShelfCode(),allocation.getFactoryCode(),allocation.getOutWarehouseCode(),1);

        return resultMap;
    }

    /**
     * 获得excel导出列表
     * @param map
     * @return List<AllocationDetail>
     */
    @Override
    public List<AllocationDetail> getAlloInExcelList(Map<String, Object> map) {
        return allocationDAO.getAlloInExcelList(map);
    }

    /**
     * 查询调拨单详细信息
     * @param id 调拨明细表主键
     * @return AllocationDetail 调拨明细
     */
    @Override
    public AllocationDetail getDetailById(Long id) {
        return allocationDAO.getDetailById(id);
    }

    /**
     * 获得仓库列表
     * @param factoryCode 厂区编码
     * @return List<Warehouse> 仓库列表
     */
    @Override
    public List<Warehouse> getWarehouseList(String factoryCode) {
        return allocationDAO.getWarehouseList(factoryCode);
    }

    /**
     * 获取库位表中未被使用的库位
     * @param warehouseCode 仓库编码
     * @param factoryCode 厂区编码
     * @return String 库位编码
     */
    @Override
    public String getRecommendShelf(String warehouseCode, String factoryCode) {
        return StringUtils.join(allocationDAO.getRecommendShelf(warehouseCode,factoryCode).stream()
                .map(Shelf::getCode).collect(Collectors.toList()), ",");
    }

    /**
     * 获取调拨入库列表数据
     * @param pageTbl
     * @param map
     * @return PageUtils
     */
    @Override
    public PageUtils getList(PageTbl pageTbl, Map<String, Object> map) {
        Page<Allocation> page = this.selectPage(new Query<Allocation>(map).getPage(), new EntityWrapper<>());
        return new PageUtils(page.setRecords(allocationDAO.getPageAlloList(page, map)));
    }

    /**
     * 调拨出库导表和调拨单管理导表
     * @param map 模糊查询条件
     * @return List<Allocation>
     */
    @Override
    public List<Allocation> getAlloStorageOutExcel(Map<String, Object> map) {
        List<Allocation> lstAllocation = allocationDAO.getAlloStorageOutExcel(map);
        lstAllocation.forEach(allocation -> {
            if (allocation.getAlloState().contains(EmumConstant.locationChangeStatus.START_CHANGE_OUT.getCode().toString())||
                allocation.getAlloState().contains(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_OUT.getCode().toString()) ||
                allocation.getAlloState().contains(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode().toString())){
                allocation.setAlloState("调拨中");
            }else if (allocation.getAlloState().contains(EmumConstant.locationChangeStatus.NOT_START.getCode().toString())){
                if (allocation.getAlloState().contains(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_IN.getCode().toString())){
                    allocation.setAlloState("调拨中");
                }else{
                    allocation.setAlloState("新建");
                }
            }else if (allocation.getAlloState().contains(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_IN.getCode().toString())){
                allocation.setAlloState("完成");
            }else{
                allocation.setAlloState("其他");
            }
        });

        return lstAllocation;
    }

    /**
     * 获取调拨流水号
     * @return int
     */
    @Override
    public int selectLatestAllocation(){
        return allocationDAO.selectLatestAllocation();
    }
}
